﻿//========================================
// All rights reserved (C) 2017-2100
// CLR 版本：	4.0.30319.42000
// 命名空间:	SFJDService
// 文 件 名：	Launcher
// 作    者：	WooG
// 联系方式：	wooglle@163.com
// 创建时间：	2018/3/20 8:34:05
//========================================
using Network.UpdateData;
using SFJDService.SocketHandle;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SFJDService
{
    /// <summary>
    /// Socket消息发射器
    /// </summary>
    public static class Launcher
    {
        static int maxThread = 100;
        static int runningThread = 0;
        static int disposedThread = 0;

        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="code">消息代码</param>
        /// <param name="msg">消息内容</param>
        public static void SendMsg2All(int code, string msg)
        {
            SendTcp2All(code, msg);
            //SendUdp2All(code, msg);
        }

        /// <summary>
        /// 给指定GUID用户发送消息
        /// </summary>
        /// <param name="code">消息代码</param>
        /// <param name="targetGuid">接收方GUID</param>
        /// <param name="msg">消息内容</param>
        /// <returns>发送成功：True; 发送失败：False</returns>
        public static bool SendMsg2One(int code, Guid targetGuid, string msg)
        {
            //SendUdp(code, targetGuid, msg);
            //return true;
            return SendTcp(code, targetGuid, msg);
        }



        /// <summary>
        /// 通过TCP向指定的IP地址发送消息
        /// </summary>
        /// <param name="code">消息代码</param>
        /// <param name="address">用户IP地址</param>
        /// <param name="msg">消息内容</param>
        private static void SendTcp(int code, IPAddress address, string msg)
        {
            IPEndPoint ipe = new IPEndPoint(address, Runtime.portMsg);
            Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                Packet packet = new Packet((Int16)code, Runtime.thisUser.UserGuid, msg);
                sSocket.Connect(ipe);
                //sSocket.SendTimeout = 2000;
                //sSocket.ReceiveTimeout = 2000;
                sSocket.Send(packet.ToBytes());
                sSocket.Shutdown(SocketShutdown.Both);
                sSocket.Close();
                sSocket.Dispose();
            }
            catch
            {
                Runtime.Printf(" UDP " + address.ToString());
                sSocket.Close();
                Guid guid = GetGuidInActives(address.ToString());/////////
                if(guid != null && guid != Guid.Empty)
                {
                    SendUdp(code, GetGuidInActives(address.ToString()), msg);
                }
                //throw;
            }
            finally
            {
                if(sSocket != null)
                {
                    sSocket.Close();
                    sSocket.Dispose();
                }
            }
        }

        /// <summary>
        /// 通过TCP向指定GUID用户发送消息
        /// </summary>
        /// <param name="code">消息代码</param>
        /// <param name="guid">用户GUID</param>
        /// <param name="msg">消息内容</param>
        /// <returns></returns>
        public static bool SendTcp(int code, Guid guid, string msg)
        {
            string ip = GetIpByGuid(guid);
            if(ip == null || ip == string.Empty)
            {
                return false;
            }
            else
            {
                try
                {
                    SendTcp(code, ip, msg);
                    return true;
                }
                catch
                {
                    SendUdp(code, ip, msg);
                    return false;
                }
            }
        }

        /// <summary>
        /// 获取指定用户的IP
        /// </summary>
        /// <param name="guid">用户GUID</param>
        /// <returns></returns>
        private static string GetIpByGuid(Guid guid)
        {
            string b = GetIpInActives(guid);
            if(b != null)
            {
                return b;
            }
            else
            {
                List<string> hosts = new LanScanning(Runtime.portMsg).GetActiveHosts();
                for (int i = hosts.Count - 1; i >= 0; i--)
                {
                    for (int j = Runtime.UsersOnLine.activeUsers.Count - 1; j >= 0; j--)
                    {
                        try //突然上线造成 索引号变化
                        {
                            if (hosts[i] == Runtime.UsersOnLine.activeUsers[j].Ip)
                            {
                                hosts.RemoveAt(i);
                            }
                        }
                        catch { }
                    }
                }
                foreach (string ip in hosts)
                {
                    SendTcp(typeof(PH07OnLine).GetDictianaryKey(), ip, Runtime.thisUser.UserName + '♠' + Runtime.version.ToString());
                }
                Thread.Sleep(1000);
                b = GetIpInActives(guid);
                return b;
            }
        }

        /// <summary>
        /// 在已激活用户中查找指定用户的IP
        /// </summary>
        /// <param name="guid">用户GUID</param>
        /// <returns></returns>
        private static string GetIpInActives(Guid guid)
        {
            List<ClassActive>.Enumerator enumerator = Runtime.UsersOnLine.activeUsers.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if(enumerator.Current.Guid != null && enumerator.Current.Guid == guid)
                {
                    return enumerator.Current.Ip;
                }
            }
            return null;
        }

        private static Guid GetGuidInActives(string ip)
        {
            List<ClassActive>.Enumerator enumerator = Runtime.UsersOnLine.activeUsers.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (enumerator.Current.Ip != null && enumerator.Current.Ip == ip)
                {
                    return enumerator.Current.Guid;
                }
            }
            return Guid.Empty;
        }

        /// <summary>
        /// 通过TCP向指定的IP地址发送消息
        /// </summary>
        /// <param name="code"></param>
        /// <param name="ip"></param>
        /// <param name="msg"></param>
        public static void SendTcp(int code, string ip, string msg)
        {
            SendTcp(code, IPAddress.Parse(ip), msg);
        }

        /// <summary>
        /// 通过TCP向所有在线用户发送消息
        /// </summary>
        /// <param name="code"></param>
        /// <param name="msg"></param>
        public static void SendTcp2All(int code, string msg)
        {
            //try
            //{
            //    List<ClassActive>.Enumerator enumerator = Runtime.UsersOnLine.activeUsers.GetEnumerator();
            //    while (enumerator.MoveNext())
            //    {
            //        SendTcp(code, enumerator.Current.Ip, msg);
            //        runningThread--;
            //        disposedThread++;
            //    }
            //}
            //catch
            //{
            //    throw;
            //}

            int count = Runtime.UsersOnLine.activeUsers.Count;
            if (count - 1 < 0)
            {
                SendTcp2All(code, msg);
            }
            else
            {
                for (int i = Runtime.UsersOnLine.activeUsers.Count - 1; i >= 0; i--)
                {
                    int index = i;
                    //Runtime.Printf("    i  " + i);
                    //Runtime.Printf("  count    " + count);
                    new Thread(() =>
                    {
                        try
                        {
                            SendTcp(code, Runtime.UsersOnLine.activeUsers[index].Ip, msg);
                        }
                        catch
                        {
                            SendUdp(code, Runtime.UsersOnLine.activeUsers[index].Ip, msg);
                        }
                        finally
                        {
                            runningThread--;
                            disposedThread++;
                        }
                    }).Start();
                    runningThread++;
                    Thread.Sleep(10);
                    while (runningThread >= maxThread) ;
                }
                while (disposedThread + 1 < Runtime.UsersOnLine.activeUsers.Count) ;
            }
        }

        private static void SendUdp(int code, string ip, string msg)
        {
            List<ClassActive>.Enumerator enumerator = Runtime.UsersOnLine.activeUsers.GetEnumerator();
            while (enumerator.MoveNext())
            {
                if(enumerator.Current.Ip == ip)
                {
                    SendUdp(code, enumerator.Current.Guid, msg);
                }
            }
        }

        /// <summary>
        /// 通过UDP向指定用户发送消息
        /// </summary>
        /// <param name="code"></param>
        /// <param name="guidTarget"></param>
        /// <param name="msg"></param>
        public static void SendUdp(int code, Guid guidTarget, string msg)
        {
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, PacketHandle.udpInPort);
            try
            {
                Packet packet = new Packet((Int16)code, Runtime.thisUser.UserGuid, guidTarget, msg);
                socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
                socket.SendTo(packet.ToBytes(), iep);
                socket.Close();
            }
            catch(Exception e)
            {
                Runtime.Printf(e.Message);
                socket.Close();
                throw;
            }
        }

        /// <summary>
        /// UDP广播消息
        /// </summary>
        /// <param name="code"></param>
        /// <param name="msg"></param>
        public static void SendUdp2All(int code, string msg)
        {
            SendUdp(code, new Guid(), msg);
        }
    }
}